#include <string.h>
#include <iostream>
using std::cout;
using std::endl;
using std::ostream;

class CowString{
    class CharProxy
    {
    public:
        CharProxy(CowString & self,int idx)
        : _self(self)
        , _idx(idx)
        {}
        
        char operator=(char ch);
        friend
        ostream & operator<<(ostream & os,const CharProxy & rhs);
    private:
        CowString & _self;
        int _idx;
    };
public:
    CowString();
    CowString(const char * pstr);
    CowString(const CowString & rhs);
    CowString & operator=(const CowString & rhs);
    ~CowString();

    int size() const{
        return strlen(_pstr);
    }

    const char * c_str() const{
        return _pstr;
    }

    int use_count() {
        return *(int*)(_pstr - kRefcountLength);
    }

    CharProxy operator[](int idx);

    friend
    ostream & operator<<(ostream & os,const CowString & rhs);
    friend
    ostream & operator<<(ostream & os,const CharProxy & rhs);
private:
    void initRefcount(){
        *(int*)(_pstr - kRefcountLength) = 1;
    }

    void increaseRefcount(){
        ++*(int*)(_pstr - kRefcountLength);
    }

    void decreaseRefcount(){
        --*(int*)(_pstr - kRefcountLength);
    }

    char * malloc(const char * pstr = nullptr){
        if(pstr){
            return new char[strlen(pstr) + 1 + kRefcountLength]() + kRefcountLength;
        }else{
            return new char[1 + kRefcountLength]() + kRefcountLength;
        }
    }

    void release(){
        decreaseRefcount();
        if(use_count() == 0){
            delete [] (_pstr - kRefcountLength);
            _pstr = nullptr;
            cout << ">> delete heap" << endl;
        }
    }


    static const int kRefcountLength = 4;
    char * _pstr;
};

ostream & operator<<(ostream & os,const CowString & rhs){
    os << rhs._pstr;
    return os;
}

CowString::CowString()
: _pstr(malloc())
{
    initRefcount();
    cout << "CowString()" << endl;
}

CowString::~CowString(){
    cout << "~cowString()" << endl;
    release();
}

CowString::CowString(const CowString & rhs)
: _pstr(rhs._pstr)//浅拷贝
{
    increaseRefcount();
    cout << "CowString(const CowString &)" << endl;
}


CowString::CowString(const char * pstr)
: _pstr(malloc(pstr))
{
    initRefcount();
    strcpy(_pstr,pstr);
    cout << "CowString(const char *)" << endl;
}

CowString & CowString::operator=(const CowString & rhs){
    if(this != &rhs){//1.考虑自复制
        release();//2.尝试回收
        _pstr = rhs._pstr;//3.浅拷贝
        increaseRefcount();//4.引用计数+1
    }
    return *this;
}

//CowString str1("hello");
//str1[0]  返回一个Charproxy对象
//这个CharProxy对象中保存了下标和一个引用（向上绑定str1）
//CharProxy对象 = 'K';
//cout << CharProxy对象
//CharProxy类分别针对接下来要进行的读操作和写操作准备运算符重载函数
CowString::CharProxy CowString::operator[](int idx){
        return CharProxy(*this,idx);    
}

char CowString::CharProxy::operator=(char ch){
    if(_idx >=0 && _idx < _self.size()){
        if(_self.use_count() > 1){
            //原来的空间引用计数-1
            _self.decreaseRefcount();
            //深拷贝 —— 写时复制
            char * ptemp = _self.malloc(_self._pstr);
            strcpy(ptemp,_self._pstr);
            //修改指向
            _self._pstr = ptemp;
            //新的空间初始化引用计数
            _self.initRefcount();
        }
        //执行写操作
        _self._pstr[_idx] = ch;
        return _self._pstr[_idx];
    }else{
        cout << "out of range!" << endl;
        char nullchar = '\0';
        return nullchar;
    }
}

//cout << str1[0]
ostream & operator<<(ostream & os,const CowString::CharProxy & rhs){
    if(rhs._idx >= 0 && rhs._idx < rhs._self.size()){
        os << rhs._self._pstr[rhs._idx];
    }else{
        os << "out of range";
    }
    return os;
}


/* char & CowString::operator[](int idx){ */
/*     if(idx >=0 && idx < size()){ */
/*         if(use_count() > 1){ */
/*             //原来的空间引用计数-1 */
/*             decreaseRefcount(); */
/*             //深拷贝 —— 写时复制 */
/*             char * ptemp = malloc(_pstr); */
/*             strcpy(ptemp,_pstr); */
/*             //修改指向 */
/*             _pstr = ptemp; */
/*             //新的空间初始化引用计数 */
/*             initRefcount(); */
/*         } */
/*         return _pstr[idx]; */
/*     }else{ */
/*         cout << "out of range!" << endl; */
/*         static char nullchar = '\0'; */
/*         return nullchar; */
/*     } */
/* } */

//测试下标访问
void test1(){
    CowString str1("hello");
    CowString str2 = str1;
    //(str1.operator[](0)).operator=('H')
    str1[0] = 'H';
    cout << str1 << endl;//Hello
    cout << str2 << endl;//hello
    cout << str1.use_count() << endl;//1
    cout << str2.use_count() << endl;//1

    cout << endl;
    CowString str3 = str1;
    //operator<<(cout,str1.operator[](0))
    cout << str1[0] << endl;//H
    cout << str1 << endl;//Hello
    cout << str2 << endl;//hello
    cout << str3 << endl;//Hello
    cout << str1.use_count() << endl;//2
    cout << str2.use_count() << endl;//1
    cout << str3.use_count() << endl;//2
}

//测试基本的复制、赋值
void test0(){
    CowString str1;
    CowString str2 = str1;
    cout << "str1:" << str1 << endl;
    cout << "str2:" << str2 << endl;
    cout << str1.use_count() << endl;
    cout << str2.use_count() << endl;

    cout << endl;
    CowString str3("hello");
    CowString str4 = str3;
    cout << "str3:" << str3 << endl;
    cout << "str4:" << str4 << endl;
    cout << str3.use_count() << endl;
    cout << str4.use_count() << endl;

    cout << endl;
    str2 = str3;
    cout << "str1:" << str1 << endl;
    cout << "str2:" << str2 << endl;
    cout << "str3:" << str3 << endl;
    cout << "str4:" << str4 << endl;
    cout << str1.use_count() << endl;
    cout << str2.use_count() << endl;
    cout << str3.use_count() << endl;
    cout << str4.use_count() << endl;
}

int main(void){
    test1();
    return 0;
}
